from scapy.all import *
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
from tkinter import *
import gmssl.sm3 as sm3
import datetime
import warnings
import make_packet
import operator

warnings.filterwarnings('ignore')


# 字符串 data 进行hash 得到定长字符串
def my_hash(data):
    b = str(data)
    if len(b) % 2 != 0:
        b += "0"
    ans_list = []
    for i in range(int(len(b) / 2)):
        temp = b[i * 2:i * 2 + 2].encode('utf-8')
        ans_list.append(sm3.sm3_kdf(temp, 2))
    ans = ""
    for i in ans_list:
        ans += i
    end = ans[len(ans) - 1] + ans[0] + ans[int(len(ans) / 3)] + ans[int(len(ans) / 2)]
    return end


def to_bytes(data):
    if isinstance(data, str):
        if len(data) % 2 != 0:
            data += '0'
            print("add '0' at end,amended: ", end="")
            print(data)
        return bytes().fromhex(data)
    elif isinstance(data, list):
        return bytes(data)
    else:
        print("only 'str' or 'list' is valid!")
        return None


def decrypt(massage, key):
    key = bytes(key, encoding='utf-8')
    sm4 = CryptSM4()
    sm4.set_key(key, SM4_DECRYPT)
    decrypt_value = sm4.crypt_ecb(to_bytes(massage))  # bytes类型
    return decrypt_value.decode(encoding='utf-8')  # 返回str


def chk_sum2(a):
    b = str(a)
    length = len(b)
    if len(b) % 2 != 0:
        b += "0"
    ans_list = []
    for i in range(int(len(b) / 2)):
        temp = b[i * 2:i * 2 + 2].encode('utf-8')

        ans_list.append(sm3.sm3_kdf(temp, 20))
    ans = ""
    for i in ans_list:
        for j in range(2):
            temp2 = str(i[j])
            temp_list = ['a', 'b', 'c', 'd', 'e', 'f']
            if temp2 in temp_list:
                temp2 = str(temp_list.index(temp2))
            ans += temp2
    return ans


def chk_sum(a):
    b = str(a)
    length = len(b)
    if len(b) % 2 != 0:
        b += "0"
    ans_list = []
    for i in range(int(len(b) / 2)):
        temp = b[i * 2:i * 2 + 2].encode('utf-8')
        ans_list.append(sm3.sm3_kdf(temp, 1))
    ans = ""
    for i in ans_list:
        for j in range(2):
            temp2 = str(i[j])

            temp_list = ['a', 'b', 'c', 'd', 'e', 'f']
            if temp2 in temp_list:
                temp2 = str(temp_list.index(temp2))
            ans += temp2

    end = ""
    for i in range(length):
        end += ans[len(ans) - 1] + ans[0] + ans[int(len(ans) / 3)] + ans[int(len(ans) / 2)]
    return ans


def pkt_sort(pkt_list):
    temp_list1 = []
    for i in (pkt_list):
        temp_list1.append(i['TCP'].seq)
    temp_list2 = temp_list1.copy()
    temp_list2.sort()
    packet_list = []
    for i in temp_list2:
        packet_list.append(pkt_list[temp_list1.index(i)])
    return packet_list


def retransmission():
    seq = 8252353
    port = 12306
    global src_ip, dst_ip, psdd
    packet = make_packet.secret_insert("0", seq, port, dst_ip, src_ip, True, psdd.get())
    for i in range(20):
        send(packet, iface="Realtek PCIe GbE Family Controller #2")


def get_key(pkt_list, pkt_end, keyy):
    time_list = []
    pool = ['000', '001', '010', '011', '100', '101', '110', '111']
    data_list = ""
    del pkt_list[-1]
    packet_list = pkt_sort(pkt_list)
    for i in packet_list:
        data_list += str(i['Raw'].load).split('?')[1].split('&')[1][2:]
    for i in pkt_list:
        time_list.append(i.time)
    # 取出尾包的校验信息
    chesum = ""
    for i in pkt_end:
        chesum += str(i['Raw'].load).split('?')[1].split('&')[1][2:]
    # 取出秘密信息
    data = []
    b_datetime_struct = datetime.datetime.fromtimestamp(time_list[0])
    for i in range(1, len(time_list)):
        e_datetime_struct = datetime.datetime.fromtimestamp(time_list[i])
        data.append((e_datetime_struct - b_datetime_struct).total_seconds())
        b_datetime_struct = e_datetime_struct
    bin_string = ""
    for i in data:
        if (i * 100 % 100 > 50):
            retransmission()
        else:
            bin_string += pool[int(i) - 1]
    word_list = []
    for i in range(int(len(bin_string) / 8)):
        if bin_string[i * 8:i * 8 + 8] != '00000000':
            word_list.append(bin_string[i * 8:i * 8 + 8])
    # 获取秘钥
    time_sentence = ""
    master = Tk()
    master.title('接收方')
    frame1 = Frame(master)
    frame1.pack(fill=X)
    for i in word_list:
        time_sentence += chr(int(i, 2))
    data_list = time_sentence + data_list[len(time_sentence):]
    keyy += "11111111111111111111111111111111111"
    if my_hash(data_list) != chesum:
        data_confirm = "完整性校验失败，重传！"
        retransmission()
    else:
        try:
            data_confirm = decrypt(data_list, keyy)
        except:
            data_confirm = "解密失败，考虑为密钥错误或网络波动较大。"
            retransmission()
    # 容器框 （LabelFrame）
    group = LabelFrame(frame1, text="解密得到信息为：", padx=5, pady=5)
    group.grid(row=2, column=0)
    w = Label(group, text=data_confirm)
    w.pack()
    master.mainloop()
    sys.exit(0)


def xor_block(left, right):
    return map(operator.xor, left, right)


def keyxor(i, temp):
    hex_string = bytes(xor_block(bytes(i, "utf-8"), bytes(temp, "utf-8"))).hex()
    temp_list = ['a', 'b', 'c', 'd', 'e', 'f']
    temp = []
    for i in range(len(hex_string)):
        if hex_string[i] in temp_list:
            temp.append(temp_list.index(hex_string[i]))
        else:
            temp.append(hex_string[i])
    end = str(temp[len(hex_string) - 1]) + str(temp[0]) + str(temp[int(len(hex_string) / 3)]) + str(
        temp[int(len(hex_string) / 2)])
    return end


def check_pkt(packet):
    global pkt_list, src_ip, dst_ip, a, psdd, time2
    key = psdd.get()
    src_ip = str(packet['IP'].src)
    dst_ip = str(packet['IP'].dst)
    time1 = time.perf_counter()
    if (a == 1):
        time2 = time.perf_counter()
        a = 2
    if str(keyxor(chk_sum(packet['TCP'].seq), key)) == str(packet["TCP"].ack):
        time2 = time.perf_counter()
        pkt_list.append(packet)
    if (time1 - time2 > 30):
        retransmission()
    if str(keyxor(chk_sum(packet['TCP'].sport), key)) == str(packet["TCP"].ack):
        pkt_list.append(packet)
        get_key(pkt_list, pkt_list[-1], psdd.get())


def helloCallBack():
    packet = sniff(iface='Realtek PCIe GbE Family Controller #2', prn=check_pkt, lfilter=lambda p: "GET" in str(p),
                   filter="tcp port 80")


def packet_callback(packet):
    src = packet['IP'].dst
    dst = packet['IP'].src
    tf = src.split(".")
    df = dst.split(".")
    src_ip = tf[0] + tf[1] + tf[2] + tf[3]
    dst_ip = df[0] + df[1] + df[2] + df[3]
    id_value = (int(src_ip) & int(dst_ip)) % 65535

    global interface
    if id_value == packet['IP'].id:  # 后续加算法的话需要更改
        data = IP(src=src, dst=dst, id=id_value) / ICMP(type=0, seq=packet[ICMP].seq)
        data.show2()
        send(data, iface=interface)  # send函数，用来返回一个应答数据包ICMP包


if __name__ == '__main__':
    interface = "Intel(R) Dual Band Wireless-AC 8265"
    sniff(filter="src host 192.168.31.35 and icmp", iface=interface, prn=packet_callback, count=1)
    src_ip = ""
    dst_ip = ""
    master = Tk()
    master.title('密钥')
    pkt_list = []
    psdd = StringVar()
    a = 1
    time2 = time.perf_counter()
    frame1 = Frame(master)
    frame1.pack(fill=X)
    label1 = Label(frame1, text='输入密钥：')
    label1.grid(row=1, column=0)
    # 输入框 (Entry)
    entryname1 = Entry(frame1, textvariable=psdd)
    entryname1.grid(row=1, column=1)
    B = Button(master, text="确认", command=helloCallBack)
    B.pack()
    master.mainloop()




